Sync to laptop - Federico
authorArturo Espinosa <unammx@src.gnome.org>
Mon, 25 Oct 1999 23:43:04 +0000 (23:43 +0000)
committerArturo Espinosa <unammx@src.gnome.org>
Mon, 25 Oct 1999 23:43:04 +0000 (23:43 +0000)
gdk-pixbuf/gnome-canvas-pixbuf.c

index 79dc9bb7c02c9e8355da78375dcd35147f573355..9b9021da84d27335da4ba2c254b34965efc4bac7 100644 (file)
@@ -21,6 +21,7 @@
  */
 
 #include <config.h>
+#include <math.h>
 #include "gdk-pixbuf.h"
 #include "gnome-canvas-pixbuf.h"
 
@@ -42,6 +43,12 @@ typedef struct {
        guint width_pixels : 1;
        guint height_set : 1;
        guint height_pixels : 1;
+
+       /* Whether the pixbuf has changed */
+       guint need_pixbuf_update : 1;
+
+       /* Whether the size has changed */
+       guint need_size_update : 1;
 } PixbufPrivate;
 
 \f
@@ -64,17 +71,26 @@ static void gnome_canvas_pixbuf_destroy (GtkObject *object);
 static void gnome_canvas_pixbuf_set_arg (GtkObject *object, GtkArg *arg, guint arg_id);
 static void gnome_canvas_pixbuf_get_arg (GtkObject *object, GtkArg *arg, guint arg_id);
 
+static void gnome_canvas_pixbuf_update (GnomeCanvasItem *item, double *affine,
+                                       ArtSVP *clip_path, int flags);
+static void gnome_canvas_pixbuf_draw (GnomeCanvasItem *item, GdkDrawable *drawable,
+                                     int x, int y, int width, int height);
+static double gnome_canvas_pixbuf_point (GnomeCanvasItem *item, double x, double y, int cx, int cy,
+                                        GnomeCanvasItem **actual_item);
+static void gnome_canvas_pixbuf_bounds (GnomeCanvasItem *item,
+                                       double *x1, double *y1, double *x2, double *y2);
+
 static GnomeCanvasItemClass *parent_class;
 
 \f
 
 /**
  * gnome_canvas_pixbuf_get_type:
- * @void: 
- * 
+ * @void:
+ *
  * Registers the &GnomeCanvasPixbuf class if necessary, and returns the type ID
  * associated to it.
- * 
+ *
  * Return value: The type ID of the &GnomeCanvasPixbuf class.
  **/
 GtkType
@@ -151,11 +167,320 @@ gnome_canvas_pixbuf_init (GnomeCanvasPixbuf *gcp)
        priv->height = 0.0;
 }
 
+/* Destroy handler for the pixbuf canvas item */
 static void
 gnome_canvas_pixbuf_destroy (GtkObject *object)
 {
+       GnomeCanvasPixbuf *gcp;
+       PixbufPrivate *priv;
+
        g_return_if_fail (object != NULL);
        g_return_if_fail (GNOME_IS_CANVAS_PIXBUF (object));
 
+       gcp = (GNOME_CANVAS_PIXBUF (object));
+       priv = gcp->priv;
+
+       /* FIXME: redraw area */
+
+       if (priv->pixbuf)
+               gdk_pixbuf_unref (priv->pixbuf);
+
+       g_free (priv);
+
+       if (GTK_OBJECT_CLASS (parent_class)->destroy)
+               (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
+}
+
+\f
+
+/* Set_arg handler for the pixbuf canvas item */
+static void
+gnome_canvas_pixbuf_set_arg (GtkObject *object, GtkArg *arg, guint arg_id)
+{
+       GnomeCanvasItem *item;
+       GnomeCanvasPixbuf *gcp;
+       PixbufPrivate *priv;
+       GdkPixbuf *pixbuf;
+       double val;
+
+       item = GNOME_CANVAS_ITEM (object);
+       gcp = GNOME_CANVAS_PIXBUF (object);
+       priv = gcp->priv;
+
+       switch (arg_id) {
+       case ARG_PIXBUF:
+               pixbuf = GTK_VALUE_POINTER (*arg);
+               if (pixbuf != priv->pixbuf) {
+                       if (pixbuf)
+                               gdk_pixbuf_ref (pixbuf);
+
+                       if (priv->pixbuf)
+                               gdk_pixbuf_unref (priv->pixbuf);
+
+                       priv->pixbuf = pixbuf;
+               }
+
+               priv->need_pixbuf_update = TRUE;
+               gnome_canvas_item_request_update (item);
+               break;
+
+       case ARG_WIDTH:
+               val = GTK_VALUE_DOUBLE (*arg);
+               g_return_if_fail (val >= 0.0);
+               priv->width = val;
+               priv->need_size_update = TRUE;
+               gnome_canvas_item_request_update (item);
+               break;
+
+       case ARG_WIDTH_SET:
+               priv->width_set = GTK_VALUE_BOOL (*arg) ? TRUE : FALSE;
+               priv->need_size_update = TRUE;
+               gnome_canvas_item_request_update (item);
+               break;
+
+       case ARG_WIDTH_PIXELS:
+               priv->width_pixels = GTK_VALUE_BOOL (*arg) ? TRUE : FALSE;
+               priv->need_size_update = TRUE;
+               gnome_canvas_item_request_update (item);
+               break;
+
+       case ARG_HEIGHT:
+               val = GTK_VALUE_DOUBLE (*arg);
+               g_return_if_fail (val >= 0.0);
+               priv->height = val;
+               priv->need_size_update = TRUE;
+               gnome_canvas_item_request_update (item);
+               break;
+
+       case ARG_HEIGHT_SET:
+               priv->height_set = GTK_VALUE_BOOL (*arg) ? TRUE : FALSE;
+               priv->need_size_update = TRUE;
+               gnome_canvas_item_request_update (item);
+               break;
+
+       case ARG_HEIGHT_PIXELS:
+               priv->height_pixels = GTK_VALUE_BOOL (*arg) ? TRUE : FALSE;
+               priv->need_size_update = TRUE;
+               gnome_canvas_item_request_update (item);
+               break;
+
+       default:
+               break;
+       }
+}
+
+/* Get_arg handler for the pixbuf canvasi item */
+static void
+gnome_canvas_pixbuf_get_arg (GtkObject *object, GtkArg *arg, guint arg_id)
+{
+       GnomeCanvasItem *item;
+       GnomeCanvasPixbuf *gcp;
+       PixbufPrivate *priv;
+
+       item = GNOME_CANVAS_ITEM (object);
+       gcp = GNOME_CANVAS_PIXBUF (object);
+       priv = gcp->priv;
+
+       switch (arg_id) {
+       case ARG_PIXBUF:
+               GTK_VALUE_POINTER (*arg) = priv->pixbuf;
+               break;
+
+       case ARG_WIDTH:
+               GTK_VALUE_DOUBLE (*arg) = priv->width;
+               break;
+
+       case ARG_WIDTH_SET:
+               GTK_VALUE_BOOL (*arg) = priv->width_set;
+               break;
+
+       case ARG_WIDTH_PIXELS:
+               GTK_VALUE_BOOL (*arg) = priv->width_pixels;
+               break;
+
+       case ARG_HEIGHT:
+               GTK_VALUE_DOUBLE (*arg) = priv->height;
+               break;
+
+       case ARG_HEIGHT_SET:
+               GTK_VALUE_BOOL (*arg) = priv->height_set;
+               break;
+
+       case ARG_HEIGHT_PIXELS:
+               GTK_VALUE_BOOL (*arg) = priv->height_pixels;
+               break;
+
+       default:
+               arg->type = GTK_TYPE_INVALID;
+               break;
+       }
+}
+
+\f
+
+/* Recomputes the bounding box of a pixbuf canvas item.  The horizontal and
+ * vertical dimensions may be specified in units or pixels, separately, so we
+ * have to compute the components individually for each dimension.
+ */
+static void
+recompute_bounding_box (GnomeCanvasPixbuf *gcp)
+{
+       GnomeCanvasItem *item;
+       PixbufPrivate *priv;
+       double i2c[6];
+       ArtPoint orig, orig_c;
+       ArtPoint i, i_c;
+       ArtPoint j, j_c;
+       double w, h;
+       double length;
+       double x1, y1, x2, y2, x3, y3, x4, y4;
+       double mx1, my1, mx2, my2;
+
+       item = GNOME_CANVAS_ITEM (gcp);
+       priv = gcp->priv;
+
+       if (!priv->pixbuf) {
+               item->x1 = item->y1 = item->x2 = item->y2 = 0.0;
+               return;
+       }
+
+       gnome_canvas_item_i2c_affine (item, i2c);
+
+       /* Our "origin" */
+
+       orig.x = 0.0;
+       orig.y = 0.0;
+       art_affine_point (&orig_c, &orig, i2c);
+
+       /* Horizontal and vertical vectors */
+
+       i.x = 1.0;
+       i.y = 0.0;
+       art_affine_point (&i_c, &i, i2c);
+
+       j.x = 0.0;
+       j.y = 1.0;
+       art_affine_point (&j_c, &j, i2c);
+
+       /* Compute size components.  If a dimension is specified in pixels, we
+        * normalize the base vector first so that it will represent the size in
+        * pixels when scaled.
+        */
+
+       /* Width */
+
+       w = 0.0;
+
+       if (priv->width_set) {
+               w = priv->width;
+
+               if (priv->width_pixels) {
+                       length = sqrt (i_c.x * i_c.x + i_c.y * i_c.y);
+
+                       if (length > GNOME_CANVAS_EPSILON) {
+                               i_c.x /= length;
+                               i_c.y /= length;
+                       } else
+                               i_c.x = i_c.y = 0.0;
+               }
+       } else if (priv->pixbuf)
+               w = priv->pixbuf->art_pixbuf->width;
+
+       i_c.x *= w;
+       i_c.y *= w;
+
+       /* Height */
+
+       h = 0.0;
+
+       if (priv->height_set) {
+               h = priv->height;
+
+               if (priv->height_pixels) {
+                       length = sqrt (j_c.x * j_c.x + j_c.y * j_c.y);
+
+                       if (length > GNOME_CANVAS_EPSILON) {
+                               j_c.x /= length;
+                               j_c.y /= length;
+                       } else
+                               j_c.x = j_c.y = 0.0;
+               }
+       } else if (priv->pixbuf)
+               h = priv->pixbuf->art_pixbuf->height;
+
+       j_c.x *= h;
+       j_c.y *= h;
+
+       /* Compute vertices */
+
+       x1 = orig.x;
+       y1 = orig.y;
+
+       x2 = orig.x + i_c.x;
+       y2 = orig.y + i_c.y;;
+
+       x3 = orig.x + j_c.x;
+       y3 = orig.y + j_c.y;
+
+       x4 = orig.x + i_c.x + j_c.x;
+       y4 = orig.y + i_c.y + j_c.y;
+
+       /* Compute bounds */
+
+       mx1 = MIN (x1, x2);
+       my1 = MIN (y1, y2);
+       mx2 = MAX (x3, x4);
+       my2 = MAX (y3, y4);
+
+       if (mx1 < mx2) {
+               item->x1 = mx1;
+               item->x2 = mx2;
+       } else {
+               item->x1 = mx2;
+               item->x2 = mx1;
+       }
+
+       if (my1 < my2) {
+               item->y1 = my1;
+               item->y2 = my2;
+       } else {
+               item->y1 = my2;
+               item->y2 = my1;
+       }
+}
+
+/* Update handler for the pixbuf canvas item */
+static void
+gnome_canvas_pixbuf_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags)
+{
+       GnomeCanvasPixbuf *gcp;
+       PixbufPrivate *priv;
+
+       gcp = GNOME_CANVAS_PIXBUF (item);
+       priv = gcp->priv;
+
+       if (parent_class->update)
+               (* parent_class->update) (item, affine, clip_path, flags);
+
+       if (((flags & GNOME_CANVAS_UPDATE_VISIBILITY)
+            && !(GTK_OBJECT_FLAGS (item) & GNOME_CANVAS_ITEM_VISIBLE))
+           || (flags & GNOME_CANVAS_UPDATE_AFFINE)
+           || priv->need_pixbuf_update
+           || priv->need_size_update)
+               gnome_canvas_request_redraw (item, item->x1, item->y1, item->x2, item->y2);
+
+       /* If we need a pixbuf update, or if the item changed visibility to
+        * shown, recompute the bounding box.
+        */
+       if (priv->need_pixbuf_update
+           || priv->need_size_update
+           || ((flags & GNOME_CANVAS_UPDATE_VISIBILITY)
+               && (GTK_OBJECT_FLAGS (ii) & GNOME_CANVAS_ITEM_VISIBLE))
+           || (flags & GNOME_CANVAS_UPDATE_AFFINE)) {
+               recompute_bounding_box (gcp);
+               gnome_canvas_request_redraw (item->canvas, item->x1, item->y1, item->x2, item->y2);
+               priv->need_pixbuf_update = FALSE;
+               priv->need_size_update = FALSE;
+       }
        
 }